package stone926.mods.more_enchantments.mixins;

import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.*;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.interfaces.IMobEntity;
import stone926.mods.more_enchantments.util.DamageUtil;
import stone926.mods.more_enchantments.util.EnchantmentUtil;

import static stone926.mods.more_enchantments.nbt.CustomNbtKeys.MOB.AI_DISABLE_TICKS;
import static stone926.mods.more_enchantments.nbt.CustomNbtKeys.MOB.TIE;

@Mixin(MobEntity.class)
public abstract class MobEntityMixin extends LivingEntity implements IMobEntity {

  private int tie = 0;
  private int aiDisableTicks = -1;

  protected MobEntityMixin(EntityType<? extends LivingEntity> entityType, World world) {
    super(entityType, world);
  }

  @Shadow
  public abstract void setAiDisabled(boolean aiDisabled);

  @Override
  public int getTie() {
    return tie;
  }

  @Override
  public void setTie(int tie) {
    this.tie = tie;
  }

  @Override
  public int getAiDisableTicks() {
    return aiDisableTicks;
  }

  @Override
  public void setAiDisableTicks(int tick) {
    aiDisableTicks = tick;
    if (tick > 0) {
      setAiDisabled(true);
      setInvulnerable(true);
    }
  }

  @Inject(method = "writeCustomDataToNbt", at = @At("HEAD"))
  private void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) {
    nbt.putInt(TIE, getTie());
    nbt.putInt(AI_DISABLE_TICKS, getAiDisableTicks());
  }

  @Inject(method = "readCustomDataFromNbt", at = @At("HEAD"))
  private void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
    if (nbt.contains(TIE)) setTie(nbt.getInt(TIE));
    if (nbt.contains(AI_DISABLE_TICKS)) setAiDisableTicks(nbt.getInt(AI_DISABLE_TICKS));
  }

  @Inject(method = "canBeLeashedBy", at = @At("RETURN"), cancellable = true)
  private void canBeLeashedBy(PlayerEntity player, CallbackInfoReturnable<Boolean> cir) {
    int tieLvl = EnchantmentHelper.getEquipmentLevel(MoreEnchantmentsMod.TIE, player);
    if (tieLvl > 0) {
      cir.setReturnValue(true);
    }
  }

  @Redirect(method = "detachLeash", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/MobEntity;dropItem(Lnet/minecraft/item/ItemConvertible;)Lnet/minecraft/entity/ItemEntity;"))
  private ItemEntity detachLeash(MobEntity instance, ItemConvertible itemConvertible) {
    return getTie() > 0 ?
      dropStack(EnchantmentUtil.enchant(new ItemStack(Items.LEAD), MoreEnchantmentsMod.TIE, getTie())) :
      instance.dropItem(itemConvertible);
  }

  @Inject(method = "interactWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/MobEntity;attachLeash(Lnet/minecraft/entity/Entity;Z)V"))
  private void interactWithItem(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
    setTie(EnchantmentHelper.getLevel(MoreEnchantmentsMod.TIE, player.getStackInHand(hand)));
  }

  @Redirect(method = "tryAttack", at = @At(value = "INVOKE", target = "Lnet/minecraft/enchantment/EnchantmentHelper;getAttackDamage(Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/EntityGroup;)F"))
  private float tryAttack(ItemStack mainhandStack, EntityGroup group, Entity en) {
    LivingEntity target = (LivingEntity) en;
    float baseAmount = EnchantmentHelper.getAttackDamage(mainhandStack, target.getGroup());
    return baseAmount + DamageUtil.getExtraDamageAmount(this, target, baseAmount);
  }

  @Inject(method = "tick", at = @At("HEAD"))
  private void disableAi(CallbackInfo ci) {
    if (aiDisableTicks > 0) aiDisableTicks--;
    else if (aiDisableTicks == 0) {
      setAiDisabled(false);
      setInvulnerable(false);
      aiDisableTicks = -1;
    }
  }

}
